package ru.spb.osll.myfit.server.execute;

import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.Iterator;
import java.util.jar.JarFile;

import fit.Fixture;
import fit.FixtureLoader;
import fit.FixtureName;
import fit.exception.CouldNotLoadComponentFitFailureException;
import fit.exception.NoSuchFixtureException;

public class MyFitFixtureLoader extends FixtureLoader {
	private URLClassLoader m_classLoader;

	public MyFitFixtureLoader(URLClassLoader classLoader) {
		this.m_classLoader = classLoader;
	}

	public Fixture disgraceThenLoad(String tableName) throws Throwable {
		FixtureName fixtureName = new FixtureName(tableName);
		Fixture fixture = instantiateFirstValidFixtureClass(fixtureName);
		addPackageToFixturePath(fixture);
		return fixture;
	}

	protected void addPackageToFixturePath(Fixture fixture) {
		Package fixturePackage = fixture.getClass().getPackage();
		if (fixturePackage != null) {
			FixtureLoader.instance().addPackageToPath(fixturePackage.getName());
		}
	}

	protected Fixture instantiateFirstValidFixtureClass(FixtureName fixtureName)
			throws Throwable {
		for (Iterator<String> i = fixtureName.getPotentialFixtureClassNames(
				FixtureLoader.instance().fixturePathElements).iterator(); i
				.hasNext();) {
			String each = (String) i.next();
			try {
				return instantiateFixture(each);
			} catch (NoSuchFixtureException ignoreAndTryTheNextCandidate) {
			}
		}

		throw new NoSuchFixtureException(fixtureName.toString());
	}

	protected Fixture instantiateFixture(String fixtureName) throws Throwable {
		Class<?> classForFixture = loadFixtureClass(fixtureName);
		Object obj = classForFixture.newInstance();
		Fixture fixture = (Fixture) obj;
		return fixture;

	}

	protected Class<?> loadFixtureClass(String fixtureName) {
		try {
			return (Class<?>) Class.forName(fixtureName, true, m_classLoader);
		} catch (ClassNotFoundException deadEnd) {
			if (deadEnd.getMessage().equals(fixtureName))
				throw new NoSuchFixtureException(fixtureName);
			else
				throw new CouldNotLoadComponentFitFailureException(
						deadEnd.getMessage(), fixtureName);
		}
	}

	public void close() {
		try {
			Class<URLClassLoader> clazz = java.net.URLClassLoader.class;
			java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp");
			ucp.setAccessible(true);
			Object sun_misc_URLClassPath = ucp.get(m_classLoader);
			java.lang.reflect.Field loaders = sun_misc_URLClassPath.getClass()
					.getDeclaredField("loaders");
			loaders.setAccessible(true);
			Object java_util_Collection = loaders.get(sun_misc_URLClassPath);
			for (Object sun_misc_URLClassPath_JarLoader : ((java.util.Collection<?>) java_util_Collection)
					.toArray()) {
				try {
					
					java.lang.reflect.Field loader = sun_misc_URLClassPath_JarLoader
							.getClass().getDeclaredField("jar");
					loader.setAccessible(true);
					Object java_util_jar_JarFile = loader
							.get(sun_misc_URLClassPath_JarLoader);
					if(java_util_jar_JarFile instanceof JarFile){
						((java.util.jar.JarFile) java_util_jar_JarFile).close();	
					}
					
				} catch (Throwable t) {
				}		
			}
						
			Class<?> MyFitLoggerClazz  = m_classLoader.loadClass("ru.spb.osll.myfit.fixtures.log.MyFitLogger");
			Method method = MyFitLoggerClazz.getMethod("closeAppenders");
			Object obj = MyFitLoggerClazz.newInstance();
			method.invoke(obj);
		} catch (Throwable t) {
		}
		return;
	}
}
